﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Linq.Dynamic.Core;
using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.JsonWebTokens;
using netCoreStudy.Auth;
using netCoreStudy.Dto.User;
using netCoreStudy.Entities;
using netCoreStudy.Entities.Parameter;
using netCoreStudy.Express;
using netCoreStudy.Helper;
using netCoreStudy.IService;
using static netCoreStudy.Helper.JwtHelper;
using static netCoreStudy.MyCommonMethod;

namespace netCoreStudy.Controllers
{
	[ApiController]
	[Route("api/login")]
	public class LoginController : ControllerBase
	{
		private readonly ILogger<LoginController> _logger;
		private readonly IUserService _userService;
		private readonly IRoleService _roleService;
		private readonly IMapper _mapper;
		private readonly PermissionRequirement _requirement;

		public LoginController(
			ILogger<LoginController> logger,
			IUserService userService,
			IRoleService roleService,
			IMapper mapper,
			PermissionRequirement requirement
		)
		{
			_logger = logger;
			_userService = userService;
			_roleService = roleService;
			_mapper = mapper;
			_requirement = requirement;
		}

		/// <summary>
		/// 用户登录 获取token
		/// </summary>
		/// <returns></returns>
		[HttpGet]
		public async Task<IActionResult> Login([FromQuery] LoginUserDto loginUserDto)
		{
			User user = await _userService.GetByNameAsync(loginUserDto.Name);
			if (user == null) return this.FailMsg("用户不存在!");

			string inputPwd = Md5Encrypt32(loginUserDto.Pass.Trim());
			if (user.Password != inputPwd) return this.FailMsg("密码不正确!");

			// 找到用户 的所有 角色 名称 
			List<string> roleNames = user.UserRoles.Select(x => x.Role.Name).ToList();

			// 获取配置文件的过期时间 _requirement 在程序启动时 就 获取了 json 的 配置
			double expirationTotalSeconds = _requirement.Expiration.TotalSeconds;
			// 新建 一个claim 列表 
			List<Claim> claims = new List<Claim>();
			// 把用户 信息加入 claim 列表
			claims.Add(new Claim(ClaimTypes.Name, user.Name));
			claims.Add(new Claim(JwtRegisteredClaimNames.Jti, user.Id.ToString()));
			claims.Add(new Claim(JwtRegisteredClaimNames.Exp,
				new DateTimeOffset(DateTime.Now.AddSeconds(expirationTotalSeconds)).ToUnixTimeSeconds().ToString()));
			// 把用户 的角色 名称s 加入 claim 列表
			claims.AddRange(roleNames.Select(roleName => new Claim(ClaimTypes.Role, roleName)));

			List<PermissionItem> list = new List<PermissionItem>();
			list.AddRange(user.UserRoles.Select(x => new PermissionItem
				{Url = "url访问控制以后再做", RoleName = x.Role.Name, RoleId = x.RoleId}));
			// 将所有的 permission 和 module 赋个值存到 _requirement permission 里面 
			_requirement.Permissions = list;
			TokenInfoViewModel token = JwtToken.BuildJwtToken(claims.ToArray(), _requirement);
			return this.SuccessMsg("登录成功", token);
		}

		/// <summary>
		/// 根据token 获取用户信息
		/// </summary>
		/// <returns></returns>
		[HttpGet("getInfo")]
		public async Task<IActionResult> GetInfo([FromQuery] string token)
		{
			try
			{
				var (id, role) = ParseJwt(token);
				User user = await _userService.GetOneByIdAsync(id);
				UserDto userDto = _mapper.Map<UserDto>(user);
				return this.SuccessMsg("获取用户信息成功!", userDto);
			}
			catch (Exception e)
			{
				return this.FailMsg("token解析失败,请重新登录!");
			}
		}

		/// <summary>
		/// 刷新token
		/// </summary>
		/// <param name="token"></param>
		/// <returns></returns>
		[HttpGet("refresh")]
		public async Task<IActionResult> RefreshToken([FromQuery] string
			token = "")
		{
			if (string.IsNullOrWhiteSpace(token))
			{
				return this.FailMsg("token是空的,请重新登录");
			}

			return this.SuccessMsg("成功", new {Id = 1, Name = "haha"});
		}

		/// <summary>
		/// 测试用
		/// </summary>
		/// <returns></returns>
		[HttpGet("test")]
		public async Task<IActionResult> Test([FromQuery] UserParameter userParameter)
		{
			IQueryable<User> query = _userService.GetAllSingle();
			query = query.WhereIf(userParameter.SearchKey != null, x => x.Name == userParameter.SearchKey);
			query = query.WhereIf(userParameter.IsRemoved != false, x => x.IsRemoved == userParameter.IsRemoved);
			List<User> listAsync = await query.ToListAsync();
			return this.SuccessMsg("嘟嘟",listAsync);
		}
	}
}